import { JSEncrypt } from 'jsencrypt';
import CryptoJS from 'crypto-js';

/**
 * 1.  public ：公共访问修饰符，表示属性或方法可以在类内部、子类和类的外部访问。
 * 2.  private ：私有访问修饰符，表示属性或方法只能在类的内部访问，无法在类的外部或子类中访问。
 * 3.  protected ：受保护的访问修饰符，表示属性或方法可以在类内部和子类中访问，但不能在类的外部访问。
 * 4.  readonly ：只读修饰符，用于将属性设置为只读，一旦赋值后就无法修改。
 * 5.  abstract ：抽象修饰符，用于定义抽象类和抽象方法。抽象类不能被实例化，而抽象方法只能在派生类中实现。
 */

/**
 * RSA 加密
 * 加密解密
 */

// !此处加密的 SSL 证书有问题，不是真实的为复制的
const KEY = {
  public:
    '-----BEGIN PUBLIC KEY-----\n' +
    'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd\n' +
    'UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs\n' +
    'HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D\n' +
    'o2kQ+X5xK9cipRgEKwIDAQAB\n' +
    '-----END PUBLIC KEY-----',
  private: 'tu_liu_xiang'
};
export const testKey = str => {
  const encryptor = new JSEncrypt();
  encryptor.setPublicKey(KEY.public);
  const rsaPw = encryptor.encrypt(str);
  console.log('rsaPw', rsaPw);
  return rsaPw;
};

export class RSA {
  // 初始化
  encrypt = new JSEncrypt();
  // 秘钥
  _public_key = 'TLX';
  _private_key = 'tu_liu_xiang';

  constructor(publicKey, privateKey) {
    if (publicKey) this._public_key = publicKey;
    if (privateKey) this._private_key = privateKey;

    // !设置公钥
    this.encrypt.setPublicKey(this._public_key);
    // !设置私钥
    this.encrypt.setPrivateKey(this._private_key);
  }

  // 声明
  get initEncrypt() {
    return (this.encrypt = new JSEncrypt());
  }

  // !加密
  encryption(str) {
    if (!str) return;
    const encrypt_value = this.encrypt.encrypt(str);
    console.log('encrypt_value 加密后的值', encrypt_value, str);
    return encrypt_value;
  }
  // !解密
  decryption(str) {
    if (!str) return;
    const decryption_value = this.encrypt.decrypt(str);
    return decryption_value;
  }
}

/**
 * !AES 对称加密
 * @param {string} str 需要加密的字符串
 * @param {string} key 加密解密的秘钥，秘钥长度可以是(8/16/32 ) 128/192/256 bit
 * @param {Object} params 其他配置
 */
export const AESEncrypt = (str, key, params) => {
  // !通过使用 CryptoJS.enc.Utf8 转换与直接传入是不一样的
  const _encryptStr = CryptoJS.enc.Utf8.parse(str);
  const _encryptKey = CryptoJS.enc.Utf8.parse(key ?? '12345678tlx~!}_?'); // '12345678tlx~!}_?'
  const _iv = CryptoJS.enc.Utf8.parse(key ?? '12345678tlx~!}_?');

  return CryptoJS.AES.encrypt(_encryptStr, _encryptKey, {
    mode: CryptoJS.mode.CBC, // 加密模式，默认为cbc，支持 cbc,ecb。cbc需要偏移量iv，ECB不需要iv
    padding: CryptoJS.pad.Pkcs7, // 填充方式。默认位Pkcs7
    iv: _iv, // 偏移向量
    ...params
  });
};

// FIXME 解密存在问题
/**
 * !AES 解密
 */
export const AESDecrypt = (secret, key) => {
  const _secret = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(secret));
  const _secretPassphrase = CryptoJS.enc.Utf8.parse(key ?? '12345678tlx~!}_?');
  const _iv = CryptoJS.enc.Utf8.parse(key ?? '12345678tlx~!}_?');

  return CryptoJS.AES.decrypt(_secret, _secretPassphrase, {
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
    iv: _iv
  });
};

export const AES = {
  _key: CryptoJS.enc.Utf8.parse('12345678tlx~!}_?'),
  _iv: CryptoJS.enc.Utf8.parse('12345678tlx~!}_?'),

  // !aes 加密
  encrypt(word) {
    let encrypted = '';
    if (typeof word == 'string') {
      const srcs = CryptoJS.enc.Utf8.parse(word);
      encrypted = CryptoJS.AES.encrypt(srcs, this._key, {
        iv: this._iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      });
    } else if (typeof word == 'object') {
      //对象格式的转成json字符串
      const data = JSON.stringify(word);
      const srcs = CryptoJS.enc.Utf8.parse(data);
      encrypted = CryptoJS.AES.encrypt(srcs, this._key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      });
    }
    return encrypted.ciphertext.toString();
  },

  // !aes 解密
  decrypt(word) {
    const encryptedHexStr = CryptoJS.enc.Hex.parse(word);
    const srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
    const decrypt = CryptoJS.AES.decrypt(srcs, this._key, {
      iv: this._iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    });
    const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
  }
};
